今天的題目在這裡: 848. Shifting Letters,被歸類為medium,乍看之下想說應該是easy頗簡單,結果還是不小心踩了幾個坑QQ 是關於char的數值範圍與int的數值範圍,還是有些知識不足的地方,一起來看看吧!
看到題目,第一眼想說只想遍歷一次的話,就要倒著來了,因為它字串的第一個字母會隨著後面的每次shift都跟著shift;然後肯定是要先記錄一個shift的總和,才知道最後總共要移多少;另外呢,要把int轉成字母/英文字母轉成int是很簡單的,你可以直接打開這個線上編譯器試試看:
// Example program
#include <iostream>
#include <string>
using namespace std;
int main()
{
int a = 'a', z = 'z';
cout << "'a' to int: " << a << endl;
cout << "'z' to int: " << z << endl;
char ca = 97, cz = 122;
cout << "97 to char: " << ca << endl;
cout << "122 to char: " << cz << endl;
}
輸出如下:
'a' to int: 97
'z' to int: 122
97 to char: a
122 to char: z
可以看到它可以動態直接轉型~ 小寫英文字母'a'~'z'的數值範圍在97~122之間。
但這裡有個陷阱,就是你如果給char x = 某數字;
,然後某數字<0 或 >255的話,就會overflow!(在unsigned char的情形中)
這是因為char
是由1byte來儲存的,容納的數值範圍只有2^8=256,char在不同編譯器中可能是signed char
或 unsigned char
,分別可接受的數值範圍是-128~127/ 0~255,可以看這邊。
順帶一提,int
則是4byte來儲存的,容納的數值範圍是2^32,從-2,147,483,648~2,147,483,647
所以來看看我一開始的寫法XD
class Solution {
public:
string shiftingLetters(string s, vector<int>& shifts) {
// iterate from the end, so we can record the nums we need to add for each char
char tmp;
int sum=0;
string ans=s;
for(int i=s.length()-1;i>=0;--i){
tmp = s[i];
sum+= shifts[i];
tmp+=sum;
if(tmp>'z'){
tmp = (tmp-'a')%26+'a';
}
ans[i] = tmp;
}
return ans;
}
};
裡面會有兩個爆點XDD
tmp+=sum
會在tmp+上去>255的時候就錯誤,sum+= shifts[i];
>2,147,483,647會溢位數值小的時候沒問題,比較大的test case就壞了
那要怎麼解決呢?就擅用提早%26
取餘數來避免最後加總才太大了!
以下是修改後的版本,順便直接拿題目的s直接修改了XD
class Solution {
public:
string shiftingLetters(string s, vector<int>& shifts) {
// record the total shift distance
int sum=0;
// iterate from the end
for(int i = shifts.size() - 1; i >= 0; --i) {
// mod in every round to ensure the range
sum = (shifts[i] + sum) % 26;
s[i] = (s[i]-'a'+sum)%26+'a';
}
return s;
}
};
本來想說題目蠻簡單,沒想到還是可以複習到一些特別的地方~
最近在看C++ Primer這本書,可能可以順便在這邊提一些書中提到的東西。